from typing import List

from emi.bar.data import BarData
from emi.util import FloatEncoder
from emi.util._NumUtils import NumUtils


class KPattern:
    _5_VALUE_PNL_ENCODE = FloatEncoder.of_list([-5, -1.5, 1.5, 5])  ## 5个
    _6_VALUE_PNL_ENCODE = FloatEncoder.of_list([-5, -2, 0, 2, 5])  ## 6个
    _7_VALUE_PNL_ENCODE = FloatEncoder.of_list([-6.5, -3.5, -1, 1, 3.5, 6.5])  ## 7个
    _8_VALUE_PNL_ENCODE = FloatEncoder.of_list([-6.5, -3.5, -1.5, 0, 1.5, 3.5, 6.5])  ## 8个
    # _3_VALUE_UP_DOWN_ENCODE = FloatEncoder.of_list([1,3])  ## 3个
    # _2_VALUE_UP_DOWN_ENCODE = FloatEncoder.of_list([1.9])  ## 2个

    @staticmethod
    def encode_by_24_value(bar: BarData):
        """"
        将一个bar编码成32个值。
        """
        pnl_close = 100 * (bar.close - bar.pre_close) / bar.pre_close
        pnl_high = 100 * (bar.high - bar.close) / bar.close
        pnl_low = 100 * (bar.low - bar.close) / bar.close

        is_high_out = abs(pnl_high) >abs(pnl_close)  ## 是否凸出来。
        is_low_out = abs(pnl_low) >=abs(pnl_close)  ## 是否凸出来。
        return KPattern._6_VALUE_PNL_ENCODE.encode(pnl_close) * 4 + int(is_high_out) * 2 + int(is_low_out)


    @staticmethod
    def encode_by_20_value(bar: BarData):
        """"
        将一个bar编码成32个值。
        """
        pnl_close = 100 * (bar.close - bar.pre_close) / bar.pre_close
        pnl_high = 100 * (bar.high - bar.close) / bar.close
        pnl_low = 100 * (bar.low - bar.close) / bar.close

        is_high_out = abs(pnl_high) >abs(pnl_close)  ## 是否凸出来。
        is_low_out = abs(pnl_low) >=abs(pnl_close)  ## 是否凸出来。
        return KPattern._5_VALUE_PNL_ENCODE.encode(pnl_close) * 4 + int(is_high_out) * 2 + int(is_low_out)

    @staticmethod
    def encode_by_28_value(bar: BarData):
        """"
        将一个bar编码成32个值。
        """
        pnl_close = 100 * (bar.close -  bar.pre_close) / bar.pre_close
        pnl_high = 100 * (bar.high -  bar.close) / bar.close
        pnl_low = 100 * (bar.low - bar.close) / bar.close

        is_high_out = abs(pnl_high) >abs(pnl_close)  ## 是否凸出来。
        is_low_out = abs(pnl_low) >=abs(pnl_close)  ## 是否凸出来。
        return KPattern._7_VALUE_PNL_ENCODE.encode(pnl_close) * 4 + int(is_high_out) * 2 + int(is_low_out)

    @staticmethod
    def encode_by_32_value(bar: BarData):
        """"
        """
        pnl_close = 100 * (bar.close - bar.pre_close) / bar.pre_close
        pnl_high = 100 * (bar.high - bar.close) / bar.close
        pnl_low = 100 * (bar.low - bar.close) / bar.close

        is_high_out = abs(pnl_high) >abs(pnl_close)  ## 是否凸出来。
        is_low_out = abs(pnl_low) >=abs(pnl_close)  ## 是否凸出来。
        return KPattern._8_VALUE_PNL_ENCODE.encode(pnl_close) * 4 + int(is_high_out) * 2 + int(is_low_out)


    @staticmethod
    def encode_by_12_value(bar:BarData):
        """
        编码|code|类别|名称|开盘价|最低价|收盘价|
        ---|---|---|---|---|---|---|
        0|UP_1|涨|高开高走| 大于preClose|大于preClose|大于openPrice|
        1|UP_2|涨|高开平走|大于preClose|大于preClose|无|
        2|UP_3|涨|高开弱高走|大于preClose|小于preClose|大于openPrice|
        3|UP_4|涨|高开弱平走|大于preClose|小于preClose|大于preClose|
        4|DOWN_1|跌|高开强低走|大于preClose|小于preClose |=最低价|
        5|DOWN_2|跌|高开弱低走|大于preClose|小于preClose|小于closePrice|
        6|UP_5|涨|低开强涨|小于preClose|=openPrice|=最高价|
        7|UP_6|涨|低开弱涨|小于preClose| 无|>preClose|
        8|DOWN_3|跌|低开强高走|小于preClose|=openPrice|=最高价|
        9|DOWN_4|跌|低开弱高走|小于preClose|无|大于收盘价|
        10|DOWN_5|跌|低开弱低走|小于preClose|无|大于最低价|
        11|DOWN_6|跌|高开强低走|小于preClose|无|=最低价|
        """
        assert bar.pre_close > 0.5
        #0-5
        high_open = bar.open >= bar.pre_close
        if high_open: # 高开
            if bar.low > bar.pre_close:
                if bar.close >= bar.open:
                    # 高开高走
                    return 0
                # 高开平走
                return 1
            else:
                if bar.close >= bar.open:
                    #高开弱高走
                    return 2
                elif bar.close >= bar.pre_close:
                    #高开弱平走
                    return 3
                else:
                    if NumUtils.is_equal(bar.close,bar.low,precision = bar.close * 0.005):
                        # 高开强低走
                        return 4
                    else:
                        #高开弱低走
                        return 5
        else:
            ##涨
            if bar.close >= bar.pre_close:
                if NumUtils.is_equal(bar.close,bar.high,precision = bar.close * 0.005) \
                    and NumUtils.is_equal(bar.open,bar.low,precision = bar.open * 0.005) :
                    #低开强涨
                    return 6
                else:
                    #低开弱涨
                    return 7
            else:
                if NumUtils.is_equal(bar.close, bar.high, precision=bar.close * 0.005) \
                        and NumUtils.is_equal(bar.open, bar.low, precision=bar.open * 0.005):
                    # 低开强高走
                    return 8
                elif bar.close > bar.open:
                    # 低开弱高走
                    return 9
                elif NumUtils.is_equal(bar.close, bar.low, precision=bar.open * 0.005):
                    #高开强低走
                    return 11
                #低开弱低走
                return 10
